import type { Service, Options, TUseRequestHandler, Result } from './index.type';
import { useCreation } from '../useCreation';
import { useEffect, useRef, useState } from 'react';
import type { MutableRefObject } from 'react';
import Fetch from './Fetch';
import { getType } from '../utils';
// import { useLoadingDelayPlugin } from './plugins/useLoadingDelayPlugin';
import { useLoadingDelayPlugin } from './plugins/useLoadingDelayPlugin'
import { useCachePlugin } from './plugins/useCachePlugin';
import { usePollingPlugin } from './plugins/usePollingPlugin';
import { useRetryPlugin } from './plugins/useRetryPlugin';
export function useRequest<TData = any, TRunArgs extends any[] = any[]>(service: Service<TData, TRunArgs>, options?: Options<TData, TRunArgs>): Result<TData, TRunArgs> {
  // 逻辑梳理：
  // Fetch中的state更新，useRequest也要更新
  const [, update] = useState<number>();
  const updateUseRequest = () => {
    // fetchInstance 是通过useRef.current定义的，所以fetchInstance.属性改变时是不会触发函数重新执行的，必须通过useState---函数重新执行--useRef.current更新。
    update(Math.random());
  };

  // plugins 要注册
  // service 是要随着 userRequest的更新而更新的
  const serviceRef = useRef<Service<TData, TRunArgs>>();
  serviceRef.current = service;
  if (!serviceRef.current || getType(serviceRef.current) !== 'function') {
    throw new Error('the first param of useRuquest service must be a Promise');
  }

  //1. Fetch只能实例化一次,但是 Fectch.options 和pluginImpls 要跟着 useRequest 的更新而更新到最新值
  // useCreation 就相当于 const fetchInstanceRef = useRef(); if (!fetchInstanceRef.current) { fetchInstanceRef.current = new Fetch(...); }
  const fetchInstance = useCreation(() => {
    const fetchInst = new Fetch(serviceRef as MutableRefObject<Service<TData, TRunArgs>>, updateUseRequest, options);
    return fetchInst;
  }, []);

  //实时跟新options
  fetchInstance.options = options ?? {};
  // 核心：把hooks放到数组里，并且多次执行数组的每一个hooks, 那么每次执行数组里的hooks函数的时候，该hooks是初始化（新建）还是更新呢？
  // 答案： 在编译阶段，该数组是确定的，数组的每一项hooks是确定的，那么就算在运行阶段手动执行该hooks,该hooks也只算更新，里面的useEffect(() => {},[]) 不会执行。(usehooks不是普通函数)
  //@ts-ignore
  fetchInstance.pluginImpls = [useLoadingDelayPlugin, useCachePlugin, usePollingPlugin, useRetryPlugin].map((plugin) => plugin(fetchInstance, options ?? {}));

  useEffect(() => {
    return () => {
      //不管文档是否可见， useEffect.destory只会在组件销毁的时候执行，
      fetchInstance.cancel();
    };
  }, []);

  return {
    loading: fetchInstance.state.loading,
    data: fetchInstance.state.data,
    error: fetchInstance.state.error,
    params: fetchInstance.state.runArgs,
    refresh: fetchInstance.refresh.bind(fetchInstance),
    refreshAsync: fetchInstance.refreshAsync.bind(fetchInstance),
    run: fetchInstance.run.bind(fetchInstance), // 不代理的话this --undefined
    runAsync: fetchInstance.runAsync.bind(fetchInstance),
    cancel: fetchInstance.cancel.bind(fetchInstance),
    mutate: fetchInstance.mutate.bind(fetchInstance),
  };
}